from typing import Dict, Any
import  re
from django.contrib.auth.models import User
from rest_framework import serializers
from django_redis import get_redis_connection
from rest_framework.exceptions import ValidationError
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate
from config.dbs.redisConfig import KEY_TEMPLATE
from .models import UserDetail,Area,Address


class UserSerializer(serializers.ModelSerializer):
    # 新增 验证码 uuid的 校验  反序列化
    # 前端能传入 write_only 能写
    verify = serializers.CharField(write_only=True)
    uuid = serializers.CharField(write_only=True)
    # 反向关联查询 一对一  模型名（小写）
    phone =serializers.CharField(source="userdetail.phone",read_only=True)
    sex =serializers.IntegerField(source="userdetail.sex",read_only=True)
    birthday =serializers.CharField(source="userdetail.birthday",read_only=True)
    avatar = serializers.CharField(source="userdetail.avatar",read_only=True)
    class Meta:
        model = User
        # fields = '__all__'
        exclude = ["first_name","groups","date_joined"
                   ,"last_login","user_permissions","is_staff",
                   "is_active"]
        extra_kwargs = {
            "password": {"write_only": True},
            "is_superuser":{"read_only":True},
        }


    # 自定义校验规则
    # 对象级别的校验
    # 拿到前端的 uuid 和 verify
    # 拿到redis的 验证码 进行比对
    def validate(self, attrs):
        # attrs = {"username":"username","verify:"","uuid":""}
        verify = attrs.get('verify') # abcd
        uuid = attrs.get('uuid')
        # 吧redis连接信息 作为参数  ==》redis缓存对象
        cache = get_redis_connection(alias='verify_codes')
        # 读取验证码内容
        redis_verify = cache.get(KEY_TEMPLATE % ("register",uuid)) # abcd
        # 当客户端输入一次验证码后  后端读取一次验证码后  验证码从数据库中删除
        cache.delete(KEY_TEMPLATE % ("register",uuid))

        # 判断是否有验证码
        if not redis_verify:
            raise serializers.ValidationError("验证码已过期")
        # 判断验证码是否一致
        if verify.upper() != redis_verify.upper():
            raise serializers.ValidationError("验证码错误")
        # 校验通过
        return attrs



# class MyTokenTokenObtainPairSerializer(serializers.Serializer):  # 原生的字段的校验的时候使用
# class MyTokenTokenObtainPairSerializer(serializers.ModelSerializer):   # 已有模型的时候

class MyTokenTokenObtainPairSerializer(TokenObtainPairSerializer):
    # serializers.Serializer  《==密码的校验《===TokenObtainSerializer  《==TokenObtainPairSerializer ===》 token返回
    # 反序列化的时候  能够让客户端传入 uuid  verify
    verify = serializers.CharField(write_only=True)
    uuid = serializers.CharField(write_only=True)

    # 校验规则
    # 对象级别的校验
    def validate(self, attrs):
        # attrs = {username:"bdtest","password":password,"verify"}
        uuid = attrs.get('uuid')
        verify = attrs.get('verify')
        username = attrs.get('username')
        password = attrs.get('password')

        # 校验  和数据库校验
        # uuid verify的校验  ===》 redis数据校验
        # 吧redis连接信息 作为参数  ==》redis缓存对象
        cache = get_redis_connection(alias='verify_codes')
        # 读取验证码内容
        redis_verify = cache.get(KEY_TEMPLATE % ("login",uuid)) # abcd
        # 当客户端输入一次验证码后  后端读取一次验证码后  验证码从数据库中删除
        cache.delete(KEY_TEMPLATE % ("login",uuid))

        # 判断是否有验证码
        if not redis_verify:
            raise serializers.ValidationError("验证码已过期")
        # 判断验证码是否一致
        if verify.upper() != redis_verify.upper():
            raise serializers.ValidationError("验证码错误")

        # 用户名和密码的校验
        user = authenticate(username=username,password=password)
        if not user:
            raise serializers.ValidationError("账号密码错误")


        # 保持会话状态 制作token令牌
        refresh = self.get_token(user)
        # 返回token 返回到客户端进行保存
        return {'user':user.username,"token":str(refresh.access_token)}



# 用户详情的序列器
class UserDetailSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserDetail
        exclude = ["is_delete"]



class UpdatePasswordSerializer(serializers.Serializer):
    password = serializers.CharField(max_length=16,min_length=6)
    new_password = serializers.CharField(max_length=16,min_length=6)
    re_new_password = serializers.CharField(max_length=16,min_length=6)


    def validate(self, attrs):
        if attrs.get('new_password') != attrs.get('re_new_password'):
            raise ValidationError("两次密码不一致")

        if attrs.get('password') == attrs.get('new_password'):
            raise ValidationError("原密码和新密码一致")

        # 原密码和数据库的密码校验
        # 怎么得到用户的数据  self.context["request"]  获取请求对象
        user = self.context["request"].user
        # user用户信息。check_password(输入密码)
        if not user.check_password(attrs.get('password')):
            raise ValidationError("原密码错误")

        return attrs



# 地区序列器
class AreaSerializer(serializers.ModelSerializer):
    class Meta:
        model = Area
        fields = ["id","name"]


# 新增 子级地区序列器
# 班级里面展示学生的数据
class ParentAreaSerializer(serializers.ModelSerializer):
    area_set = AreaSerializer(many=True, read_only=True)
    class Meta:
        model = Area
        fields = ["id","name","area_set"]

# 收货地址序列器
class AddressSerializer(serializers.ModelSerializer):
    province_name = serializers.CharField(read_only=True,source="province.name")
    city_name = serializers.CharField(read_only=True,source="city.name")
    district_name = serializers.CharField(read_only=True,source="district.name")
    class Meta:
        model = Address
        exclude = ["is_delete"]


    # 属性级别的校验
    def validate_mobile(self, values):
        if not re.match(r"1[3-9]\d{9}",values):
            raise serializers.ValidationError("手机号格式不正确")
        return values